package monitor

import (
	"context"
	"os"
	"sync"
	"time"
)

type TickerIntervalEnginner struct {
	lk     sync.RWMutex
	dura   time.Duration
	fn     func()
	stopFn func()
}

func NewTickerIntervalEnginner(dura time.Duration) *TickerIntervalEnginner {
	rval := &TickerIntervalEnginner{dura: dura}
	ctx, cancel := context.WithCancel(context.Background())
	rval.stopFn = cancel
	go rval.start(ctx)
	return rval
}

func (this *TickerIntervalEnginner) start(ctx context.Context) {
	ticker := time.NewTicker(this.dura)
labelFor:
	for {
		select {
		case <-ticker.C:
			go this.doInterval()
		case <-ctx.Done():
			break labelFor
		}
	}
}

func (this *TickerIntervalEnginner) Close() error {
	this.lk.Lock()
	defer this.lk.Unlock()
	if this.stopFn != nil {
		this.stopFn()
		this.stopFn = nil
		return nil
	}
	return os.ErrClosed
}

func (this *TickerIntervalEnginner) doInterval() {
	this.lk.RLock()
	defer this.lk.RUnlock()
	if this.fn != nil {
		this.fn()
	}
}

func (this *TickerIntervalEnginner) SetInterval(fn func()) {
	this.lk.Lock()
	defer this.lk.Unlock()
	this.fn = fn
}

func init() {
	SetIntervalEngineer(NewTickerIntervalEnginner(time.Millisecond * 1100))
}
